﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Controls;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using HP.Cachalote.DataModels;
using HP.Cachalote.Services.Interfaces;
using HP.Cachalote.WPF.Model;
using HP.Cachalote.WPF.Shared;

namespace HP.Cachalote.WPF.ViewModel
{
    /// <summary>
    /// This class contains properties that a View can data bind to.
    /// <para>
    /// See http://www.galasoft.ch/mvvm
    /// </para>
    /// </summary>
    public class DueTimeDisplayViewModel : MyViewModelBase
    {
        public const string RequestDisplayDueDateTimePickerMessageToken = "RequestDisplayDueDateTimePickerMessage";
        public const string DueDateChangedMessageToken = "DueDateChanged";

        public int TodoItemID { get; set; }
        public DateTime? DueDate { get; set; }
        public DateTime? StartTime { get; set; }
        public DateTime? EndTime { get; set; }

        // The property will store the DueDate before changed. 
        // It is used by FilterList to calculate the related TodoItem Count with hit database again.
        public DateTime? PreChangedDueDate { get; set; }

        /// <summary>
        /// Initializes a new instance of the DueTimeDisplayViewModel class.
        /// </summary>
        public DueTimeDisplayViewModel(IDataService dataService)
            : base(dataService) { }

        /// <summary>
        /// Register all necessary messages. It is called by constructor in base class.
        /// </summary>
        protected override void RegisterMessages()
        {
            // Get SelectDueDateTimeCompleteMessage from DueTimePickerViewModel to update the DueDate & Time once it is updated.
            Messenger.Default.Register<DueTimePickerViewModel>(this, DueTimePickerViewModel.SelectDueDateTimeCompleteMessageToken,
                dueTimePickerViewModel => PickDueDateComplete(dueTimePickerViewModel));
        }

        /// <summary>
        /// The <see cref="DueDateDisplay" /> property's name.
        /// </summary>
        public const string DueDateDisplayPropertyName = "DueDateDisplay";

        private string _dueDateDisplay = string.Empty;

        /// <summary>
        /// Sets and gets the DueDateDisplay property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public string DueDateDisplay
        {
            get
            {
                return _dueDateDisplay;
            }

            set
            {
                if (_dueDateDisplay == value)
                {
                    return;
                }

                RaisePropertyChanging(DueDateDisplayPropertyName);
                _dueDateDisplay = value;
                RaisePropertyChanged(DueDateDisplayPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="DueTimeDisplay" /> property's name.
        /// </summary>
        public const string DueTimeDisplayPropertyName = "DueTimeDisplay";

        private string _dueTimeDisplay = string.Empty;

        /// <summary>
        /// Sets and gets the DueTimeDisplay property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public string DueTimeDisplay
        {
            get
            {
                return _dueTimeDisplay;
            }

            set
            {
                if (_dueTimeDisplay == value)
                {
                    return;
                }

                RaisePropertyChanging(DueTimeDisplayPropertyName);
                _dueTimeDisplay = value;
                RaisePropertyChanged(DueTimeDisplayPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="DueDateStatus" /> property's name.
        /// </summary>
        public const string DueDateStatusPropertyName = "DueDateStatus";

        private DueDateStatus _dueDateStatus;

        /// <summary>
        /// Sets and gets the DueDateStatus property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public DueDateStatus DueDateStatus
        {
            get
            {
                return _dueDateStatus;
            }

            set
            {
                if (_dueDateStatus == value)
                {
                    return;
                }

                RaisePropertyChanging(DueDateStatusPropertyName);
                _dueDateStatus = value;
                RaisePropertyChanged(DueDateStatusPropertyName);
            }
        }

        private RelayCommand _showDueDateTimePickerCommand;

        /// <summary>
        /// Gets the ShowDueTimePicker.
        /// </summary>
        public RelayCommand ShowDueDateTimePickerCommand
        {
            get
            {
                return _showDueDateTimePickerCommand
                    ?? (_showDueDateTimePickerCommand = new RelayCommand(
                                          () =>
                                          {
                                              // Send message to TodoItemTreeViewItemViewModel to request display DueDateTimePicker.
                                              Messenger.Default.Send<int>(TodoItemID, RequestDisplayDueDateTimePickerMessageToken);
                                          }));
            }
        }

        /// <summary>
        /// This method will be called by DueTimePickerViewModel when the Due Date & Time selection is complete.
        /// </summary>
        /// <param name="dueTimePickerViewModel">The instance of DueTimePickerViewModel.</param>
        private void PickDueDateComplete(DueTimePickerViewModel dueTimePickerViewModel)
        {
            if (dueTimePickerViewModel.TodoItemID == TodoItemID && 
                (dueTimePickerViewModel.DueDate != DueDate || 
                dueTimePickerViewModel.StartTime != StartTime || 
                dueTimePickerViewModel.EndTime != EndTime))
            {
                // Update DueTimeDisplayViewModel and request to change the display.
                DueDate = dueTimePickerViewModel.DueDate;

                // Set the StartTime
                if (dueTimePickerViewModel.StartTime.HasValue)
                {
                    StartTime = dueTimePickerViewModel.DueDate.Value.Date.Add(dueTimePickerViewModel.StartTime.Value.TimeOfDay);
                }
                else
                {
                    StartTime = null;
                }

                // Set the EndTime
                if (dueTimePickerViewModel.EndTime.HasValue)
                {
                    EndTime = dueTimePickerViewModel.DueDate.Value.Date.Add(dueTimePickerViewModel.EndTime.Value.TimeOfDay);
                }
                else
                {
                    EndTime = null;
                }

                // Set DueDateDisplay
                DueDateDisplay = InformationFormatter.FormatDueDateDisplay(DueDate);

                // Set DueTimeDisplay
                DueTimeDisplay = InformationFormatter.FormatDueTimeDisplay(DueDate, StartTime, EndTime);

                // Save the update
                ChangeDueDate();

                // Send the message once DueDate has been changed. Send to TodoItemFilterViewModel and TodoItemTreeViewItemViewModel.
                Messenger.Default.Send<DueTimeDisplayViewModel>(this, DueDateChangedMessageToken);
            }

            // Send Message to DueTimePickerWindow to close it.
            Messenger.Default.Send<int>(0, DueTimePickerViewModel.RequestCloseDueTimePickerWindowMessageToken);
        }

        /// <summary>
        /// Save the changed due date & time.
        /// </summary>
        public void ChangeDueDate()
        {
            var todoItemService = ServiceFactory.CreateTodoItemService();
            var todoItem = todoItemService.Get(TodoItemID);

            if (todoItem != null)
            {
                // If current value has been changed.
                if (DueDate != todoItem.DueDate || StartTime != todoItem.StartTime || EndTime != todoItem.EndTime)
                {
                    PreChangedDueDate = todoItem.DueDate;
                    todoItem.DueDate = DueDate;
                    todoItem.StartTime = StartTime;
                    todoItem.EndTime = EndTime;

                    todoItemService.Update(todoItem);
                }
            }
        }
    }
}